// enum_dispatch将为RespFrame自动实现RespEncode trait, 同时自动为每一个变体实现From trait
// 自动实现的RespEncode trait的类似代码:
// impl RespEncode for RespFrame {
//     fn encode(&self) -> Vec<u8> {
//         match self {
//             RespFrame::SimpleString(s) => s.encode(),
//              ... 其他变体
//         }
//     }
// }
// 自动实现From trait的类似代码:
// impl From<SimpleString> for RespFrame {
//     fn from(value: SimpleString) -> Self {
//         RespFrame::SimpleString(value)
//     }
// }

use bytes::BytesMut;
use enum_dispatch::enum_dispatch;

use crate::{
    BulkString, RespArray, RespDecode, RespError, RespMap, RespNull, RespNullArray,
    RespNullBulkString, RespSet, SimpleError, SimpleString,
};

// impl From<SimpleError> for RespFrame {
//     fn from(value: SimpleError) -> Self {
//         RespFrame::Error(value)
//     }
// }
#[enum_dispatch(RespEncode)]
#[derive(Debug, PartialEq, Clone)]
pub enum RespFrame {
    SimpleString(SimpleString),
    Error(SimpleError),
    Integer(i64),
    BulkString(BulkString),
    NullBulkString(RespNullBulkString),
    Array(RespArray),
    NullArray(RespNullArray),
    Null(RespNull),
    Boolean(bool),
    Double(f64),
    Map(RespMap),
    Set(RespSet),
}

impl RespDecode for RespFrame {
    fn decode(buf: &mut BytesMut) -> Result<Self, RespError> {
        let mut iter = buf.iter().peekable();
        match iter.peek() {
            Some(b'+') => Ok(SimpleString::decode(buf)?.into()),
            Some(b'-') => Ok(SimpleError::decode(buf)?.into()),
            Some(b'$') => match RespNullBulkString::decode(buf) {
                Ok(frame) => Ok(frame.into()),
                Err(RespError::NotComplete) => Err(RespError::NotComplete),
                Err(_) => Ok(BulkString::decode(buf)?.into()),
            },
            Some(b'_') => Ok(RespNull::decode(buf)?.into()),
            Some(b'*') => match RespNullArray::decode(buf) {
                Ok(frame) => Ok(frame.into()),
                Err(RespError::NotComplete) => Err(RespError::NotComplete),
                Err(_) => Ok(RespArray::decode(buf)?.into()),
            },
            Some(b':') => Ok(i64::decode(buf)?.into()),
            Some(b'#') => Ok(bool::decode(buf)?.into()),
            Some(b',') => Ok(f64::decode(buf)?.into()),
            Some(b'~') => Ok(RespSet::decode(buf)?.into()),
            Some(b'%') => Ok(RespMap::decode(buf)?.into()),
            None => Err(RespError::NotComplete),
            _ => Err(RespError::InvalidFrame(format!(
                "unknown frame: {}",
                String::from_utf8_lossy(&buf[..])
            ))),
        }
    }
}
